﻿using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using Wicture.DbRESTFul;
using Wicture.DbRESTFul.SQL;
using Wicture.EPC.Common;
using Wicture.EPC.Common.Biz;
using Wicture.EPC.Service.V1.Filters;
using Wicture.EPC.Service.V1.Models;
using Wicture.EPC.Service.V1.Repository;
using Wicture.EPC.Service.V1.Resources;

namespace Wicture.EPC.Service.V1.QueryInterceptors.Interceptors
{
    public class NissanQueryInterceptor : BaseQueryInterceptor
    {
        private string[] brandCodes = new string[] { "nissan", "infiniti", "venucia" };

        public override string[] BrandCodes => brandCodes;

        public override object QueryModel(DbRESTFulRepository repository, JObject param)
        {
            Get_Model_InfoParam modelParam = param.ToObject<Get_Model_InfoParam>();
            Get_Model_InfoResult result = new Get_Model_InfoResult();
            if (!string.IsNullOrEmpty(modelParam.vin))
            {
                var vinInfo = repository.Invoke(CSIs.Query_Vin_By_Code_For_Nissan, modelParam);
                if (vinInfo == null)
                {
                    throw new LogicalException($"未找到该Vin码(nissan):{modelParam.vin}", 610);
                }

                string modelCode = vinInfo.modelCode;
                int positionCode = vinInfo.positionCode;
                string yearMonth = vinInfo.yearMonth;
                result = JObject.FromObject(vinInfo).ToObject<Get_Model_InfoResult>();
                result.props = new List<Get_Model_InfoResult._props>();
                result.props.Add(new Get_Model_InfoResult._props { key = "车型", value = vinInfo.name });
                result.props.Add(new Get_Model_InfoResult._props { key = "生产日期", value = DateOperator.GetYearMonthStr(yearMonth.ToInt()) });
                result.props.Add(new Get_Model_InfoResult._props { key = "车系", value = vinInfo.modelSeries });
                result.props.Add(new Get_Model_InfoResult._props { key = "车型代码", value = vinInfo.model });
                result.props.Add(new Get_Model_InfoResult._props { key = "Color :#", value = vinInfo.accCode });
                result.props.Add(new Get_Model_InfoResult._props { key = "Int.Color", value = vinInfo.trimCode });
                result.props.Add(new Get_Model_InfoResult._props { key = "车架号", value = modelParam.vin });

                result.features = new List<Get_Model_InfoResult._features>();
                List<Feature_Nissan> features = GetFeatures(modelCode);
                var combine = GetFeatureCombines(modelCode, positionCode, yearMonth).FirstOrDefault();
                features = FilterFeaturesByCombine(features, combine);
                foreach (var feature in features)
                {
                    result.features.Add(new Get_Model_InfoResult._features { key = feature.code, value = feature.name });
                }
            }
            else
            {
                var ids = modelParam.id.Split("_");
                if (ids.Count() > 1)
                {
                    modelParam.id = ids[1];
                }
                var model = repository.Invoke(CSIs.Get_Model, modelParam);
                if (model != null)
                {
                    result = JObject.FromObject(model).ToObject<Get_Model_InfoResult>();
                    result.props = GetModelProps(repository, param);
                }
            }
            return result;
        }

        private List<Feature_Nissan> GetFeatures(string modelCode)
        {
            modelCode = modelCode.TrimStart('0');
            List<Feature_Nissan> features = new List<Feature_Nissan>();
            if (ResourceHelper.NissanFeatureDict.ContainsKey(modelCode))
            {
                features = ResourceHelper.NissanFeatureDict[modelCode];
            }
            return features;
        }

        private List<Feature_Nissan_Combine> GetFeatureCombines(string modelCode, int? positionCode, string yearMonth)
        {
            modelCode = modelCode.TrimStart('0');
            List<Feature_Nissan_Combine> combines = new List<Feature_Nissan_Combine>();
            if (ResourceHelper.NissanFeatureCombineDict.ContainsKey(modelCode))
            {
                combines = ResourceHelper.NissanFeatureCombineDict[modelCode];
            }
            if (positionCode.HasValue)
            {
                combines = combines.Where(q => q.positionCode == positionCode.Value).ToList();
            }
            if (!string.IsNullOrEmpty(yearMonth) && combines.Count > 1)
            {
                combines = combines.Where(q => (string.IsNullOrEmpty(q.fromDate) || DateOperator.ComparerDate(Convert.ToInt32(q.fromDate), Convert.ToInt32(yearMonth)) <= 0) && (string.IsNullOrEmpty(q.toDate) || DateOperator.ComparerDate(Convert.ToInt32(q.toDate), Convert.ToInt32(yearMonth)) >= 0)).ToList();
            }
            return combines;
        }

        private List<Feature_Nissan> FilterFeaturesByCombine(List<Feature_Nissan> features, Feature_Nissan_Combine combine)
        {
            if (combine == null)
            {
                return features;
            }
            List<Feature_Nissan> retList = new List<Feature_Nissan>();
            if (!string.IsNullOrEmpty(combine.attr1))
            {
                retList.Add(features.Where(q => q.attrIndex == 1 && q.code == combine.attr1).First());
            }
            if (!string.IsNullOrEmpty(combine.attr2))
            {
                retList.Add(features.Where(q => q.attrIndex == 2 && q.code == combine.attr2).First());
            }
            if (!string.IsNullOrEmpty(combine.attr3))
            {
                retList.Add(features.Where(q => q.attrIndex == 3 && q.code == combine.attr3).First());
            }
            if (!string.IsNullOrEmpty(combine.attr4))
            {
                retList.Add(features.Where(q => q.attrIndex == 4 && q.code == combine.attr4).First());
            }
            if (!string.IsNullOrEmpty(combine.attr5))
            {
                retList.Add(features.Where(q => q.attrIndex == 5 && q.code == combine.attr5).First());
            }
            if (!string.IsNullOrEmpty(combine.attr6))
            {
                retList.Add(features.Where(q => q.attrIndex == 6 && q.code == combine.attr6).First());
            }
            if (!string.IsNullOrEmpty(combine.attr7))
            {
                retList.Add(features.Where(q => q.attrIndex == 7 && q.code == combine.attr7).First());
            }
            if (!string.IsNullOrEmpty(combine.attr8))
            {
                retList.Add(features.Where(q => q.attrIndex == 8 && q.code == combine.attr8).First());
            }
            return retList;
        }

        protected override List<Query_PartsResult> GetParts(DbRESTFulRepository repository, JObject param)
        {
            return repository.Invoke<Query_PartsResult>(CSIs.Query_Parts_For_Nissan, param);
        }
        protected override List<Query_PartsResult> BuildPartResults(List<Query_PartsResult> result)
        {
            List<Query_PartsResult> res = new List<Query_PartsResult>();
            //特殊处理,超过1w取3千
            if (result != null && result.Count() > 3000)
            {
                var groupedList = result.GroupBy(e => e.imageSN);
                foreach (var item in groupedList)
                {
                    res.AddRange(item.Where(e => e.belongToVin).Take(20));
                }
            }
            else
            {
                res = result;
            }
            foreach (var item in res)
            {
                if (item.startTime.HasValue || item.endTime.HasValue)
                {
                    item.notes += $"{DateOperator.GetYearMonthStr(item.startTime)} - {DateOperator.GetYearMonthStr(item.endTime)}";
                }
                if (!string.IsNullOrEmpty(item.description))
                {
                    item.notes += $"$$Specification:{item.description}";
                }
                if (!string.IsNullOrEmpty(item.featureCodes))
                {
                    item.notes += $"$$Spec Code:{item.featureCodes}";
                }
                if (!string.IsNullOrEmpty(item.trimColor))
                {
                    item.notes += $"$$Trim Color:{item.trimColor}";
                }
                if (!string.IsNullOrEmpty(item.bodyColor))
                {
                    item.notes += $"$$Body Color:{item.bodyColor}";
                }
                if (!string.IsNullOrEmpty(item.country))
                {
                    item.notes += $"$$Country:{item.country}";
                }
                if (!string.IsNullOrEmpty(item.notes) && item.notes.StartsWith("$$"))
                {
                    item.notes = item.notes.Substring(2);
                }
            }

            return res.GroupBy(q => new { q.imageSN, q.partCode, q.partName, q.notes, q.modelNotes, q.quantity, q.price, q.cost, q.priceUpdatedAt, q.replacedPartCodes, q.brandCode, q.brandName, q.belongToVin }).Select(q => new { q.Key.imageSN, q.Key.partCode, q.Key.partName, q.Key.notes, q.Key.modelNotes, q.Key.quantity, q.Key.price, q.Key.cost, q.Key.priceUpdatedAt, q.Key.replacedPartCodes, q.Key.brandCode, q.Key.brandName, q.Key.belongToVin, id = q.Select(x => x.id).FirstOrDefault() })
                .Select(q => new Query_PartsResult { imageSN = q.imageSN, partCode = q.partCode, partName = q.partName, notes = q.notes, modelNotes = q.modelNotes, quantity = q.quantity, price = q.price, cost = q.cost, priceUpdatedAt = q.priceUpdatedAt, replacedPartCodes = q.replacedPartCodes, brandCode = q.brandCode, brandName = q.brandName, belongToVin = q.belongToVin, id = q.id, pricehidden = true }).ToList();
        }

        protected override List<Query_SubGroupResult> BuildSubGroupResults(List<Query_SubGroupResult> result)
        {
            foreach (var item in result)
            {
                item.imageSN = item.code + '-' + item.imageSN;
                item.remark = $"{DateOperator.GetYearMonthStr(item.startTime)} - {DateOperator.GetYearMonthStr(item.endTime)}";
            }
            return result;
        }
        protected override void FilterPartsByVin(DbRESTFulRepository repository, ref List<Query_PartsResult> result, string vin, string selectorId)
        {
            if (!result.Any())
            {
                return;
            }
            var refSubGroupCodes = result.Where(q => string.IsNullOrEmpty(q.partCode) && q.imageSN != null && q.imageSN.Length == 3).Select(q => q.imageSN).Distinct();
            IEnumerable<Query_SubGroupResult> refSubGroups = repository.Invoke<Query_SubGroupResult>(CSIs.Query_SubGroup_By_Codes_For_Nissan, new { selectorId, subGroupCodes = refSubGroupCodes });
            if (!string.IsNullOrEmpty(vin))
            {
                var vinInfo = repository.Invoke(CSIs.Query_Vin_By_Code_For_Nissan, new { vin });
                if (vinInfo != null)
                {
                    string modelCode = vinInfo.modelCode;
                    int positionCode = vinInfo.positionCode;
                    string yearMonth = vinInfo.yearMonth;
                    int productionDate = yearMonth.ToInt();

                    var features = GetFeatures(modelCode);
                    var combine = GetFeatureCombines(modelCode, positionCode, yearMonth).FirstOrDefault();
                    features = FilterFeaturesByCombine(features, combine);

                    ISet<string> featureCodes = new HashSet<string>(features.Select(q => q.code));
                    UCString uCString = GetNissanUCString();
                    string trimCode = vinInfo.trimCode;
                    string accCode = vinInfo.accCode;
                    string specCodes = vinInfo.specCodes;

                    FilterSubGroupsByVinInfo(refSubGroups, productionDate, specCodes, featureCodes);
                    foreach (var item in result)
                    {
                        if (!DateOperator.ComparerDate(item.startTime, item.endTime, productionDate, productionDate))
                        {
                            item.belongToVin = false;
                            continue;
                        }

                        if (!string.IsNullOrEmpty(trimCode) && !string.IsNullOrEmpty(item.trimColor))
                        {
                            if (!item.trimColor.Contains(trimCode))
                            {
                                item.belongToVin = false;
                                continue;
                            }
                        }

                        if (!string.IsNullOrEmpty(accCode) && !string.IsNullOrEmpty(item.bodyColor))
                        {
                            accCode = accCode.Split(' ')[0];
                            var pass = false;
                            for (int i = 0; i < item.bodyColor.Length / 3; i++)
                            {
                                if (item.bodyColor.Substring(i * 3, 3) == accCode)
                                {
                                    pass = true;
                                    break;
                                }
                            }
                            if (!pass)
                            {
                                item.belongToVin = false;
                                continue;
                            }
                        }

                        if (!string.IsNullOrEmpty(specCodes) && !string.IsNullOrEmpty(item.featureCodes))
                        {
                            var featureArray = item.featureCodes.Split(',');
                            if (featureArray.Any(q => !specCodes.Contains(q) && !q.Equals("*****")))
                            {
                                item.belongToVin = false;
                                continue;
                            }
                            item.weight += featureArray.Length;
                        }


                        if (!string.IsNullOrEmpty(item.modelFilter))
                        {
                            uCString.BuildBCode(item.modelFilter);
                            if (!uCString.IsMatch(featureCodes))
                            {
                                item.belongToVin = false;
                                continue;
                            }
                            item.weight += 10;
                        }
                    }

                    var weightDic = result.Where(q => q.belongToVin).GroupBy(q => q.imageSN).ToDictionary(k => k.Key, v => v.Max(p => p.weight));
                    foreach (var item in result)
                    {
                        if (item.belongToVin && weightDic[item.imageSN] != item.weight)
                        {
                            item.belongToVin = false;
                        }
                    }
                }
            }

            //build ref subgroup;
            foreach (var item in result)
            {
                if (!string.IsNullOrEmpty(item.partCode) || item.imageSN == null || item.imageSN.Length != 3)
                {
                    continue;
                }
                var refSubGroup = refSubGroups.Where(q => q.belongTo && q.code == item.imageSN).FirstOrDefault();
                if (refSubGroup == null)
                {
                    continue;
                }
                item.notes = $"参见: <a data='mainGroupId={refSubGroup.mainGroupId},subGroupId={refSubGroup.id}'>{item.imageSN}</a>";
            }

            (from q in result.Where(q => q.belongToVin && !string.IsNullOrEmpty(q.replacedPartCodes))
             join p in result.Where(p => p.belongToVin && !string.IsNullOrEmpty(p.partCode)) on new { partCode = q.replacedPartCodes, q.imageSN } equals new { p.partCode, p.imageSN }
             select q).ForEach(x => x.belongToVin = false);
        }

        protected override IEnumerable<dynamic> GetHotPoints(DbRESTFulRepository repository, JObject param)
        {
            return repository.Invoke(CSIs.Query_HotPoints_For_Nissan, param);
        }

        private UCString GetNissanUCString()
        {
            UCString uCString = new UCString('.', ':', '+');
            uCString.SetIgnoreChars(new List<char> { '*' });
            return uCString;
        }

        protected override IEnumerable<Query_SubGroupResult> GetSubGroup(DbRESTFulRepository repository, JObject param)
        {
            return repository.Invoke<Query_SubGroupResult>(CSIs.Query_SubGroup_For_Nissan, param);
        }

        protected override List<Query_SubGroupResult> FilterSubGroupsByVin(DbRESTFulRepository repository, List<Query_SubGroupResult> results, JObject param)
        {
            var vin = param.Value<string>(ParamFields._vin);
            if (string.IsNullOrEmpty(vin) || results == null || results.Count == 0)
            {
                return results;
            }
            var vinInfo = repository.Invoke(CSIs.Query_Vin_By_Code_For_Nissan, new { vin });
            if (vinInfo != null)
            {
                string modelCode = vinInfo.modelCode;
                int positionCode = vinInfo.positionCode;
                string yearMonth = vinInfo.yearMonth;
                int productionDate = yearMonth.ToInt();
                string specCodes = vinInfo.specCodes;

                var features = GetFeatures(modelCode);
                var combine = GetFeatureCombines(modelCode, positionCode, yearMonth).FirstOrDefault();
                features = FilterFeaturesByCombine(features, combine);

                ISet<string> featureCodes = new HashSet<string>(features.Select(q => q.code));
                FilterSubGroupsByVinInfo(results, productionDate, specCodes, featureCodes);

                //时间过滤
                var tempGroups = results.Where(q => q.belongTo && !q.endTime.HasValue).GroupBy(q => q.code);
                foreach (var group in tempGroups)
                {
                    var maxDate = group.Max(q => q.startTime);
                    group.Where(q => q.startTime != maxDate).ForEach(q => q.belongTo = false);
                }
            }
            return results;
        }
        private void FilterSubGroupsByVinInfo(IEnumerable<Query_SubGroupResult> results, int productionDate, string specCodes, ISet<string> featureCodes)
        {
            if (!results.Any())
            {
                return;
            }
            UCString uCString = GetNissanUCString();
            foreach (var item in results)
            {
                if (!DateOperator.ComparerDate(item.startTime, item.endTime, productionDate, productionDate))
                {
                    item.belongTo = false;
                    continue;
                }
                //if (!string.IsNullOrEmpty(specCodes) && !string.IsNullOrEmpty(item.specCodes))
                //{
                //    var featureArray = item.specCodes.Split(',');
                //    if (featureArray.Any(q => !specCodes.Contains(q)))
                //    {
                //        item.belongTo = false;
                //        continue;
                //    }
                //}
                if (!string.IsNullOrEmpty(item.applicableModel))
                {
                    uCString.BuildBCode(item.applicableModel);
                    if (!uCString.IsMatch(featureCodes))
                    {
                        item.belongTo = false;
                        continue;
                    }
                }
            }
        }

        public override object QueryPartDetail(DbRESTFulRepository repository, JObject param)
        {
            param.RemoveEmptyValues();
            var brandCode = param.Value<string>(ParamFields._brandCode);
            var partId = param.Value<string>(ParamFields._partId);
            var partCode = param.Value<string>(ParamFields._partCode);
            var realPartCode = partCode;
            dynamic data = null;
            bool isSupplierPartCode = false;
            if (string.IsNullOrEmpty(partId))
            {
                //var supplierPart = repository.Invoke(CSIs.Get_Single_Supplier_Part_For_Nissan, new { supplierPartCode = partCode, brandCode });
                //if (supplierPart != null)
                //{
                //    isSupplierPartCode = true;
                //    realPartCode = supplierPart.partCode;
                //}
                //else
                //{
                //    realPartCode = partCode;
                //}
                data = repository.Invoke(CSIs.Get_Part_Detail_For_Nissan, new { partCode = realPartCode, brandCode });
                //if (isSupplierPartCode)
                //{
                //    data.partCode = supplierPart.supplierPartCode;
                //    data.price = supplierPart.price;
                //    data.cost = supplierPart.cost;
                //    data.priceUpdatedAt = supplierPart.priceUpdatedAt;
                //    data.disabled = supplierPart.disabled;
                //}
            }
            else
            {
                data = repository.Invoke(CSIs.Get_Usage_Detail_For_Nissan, param);
            }
            if (data == null) return null;
            // 1、基本信息赋值
            Query_Part_DetailResult result = JObject.FromObject(data).ToObject<Query_Part_DetailResult>();

            var brandName = BrandDictionary.GetName(brandCode);
            if (!isSupplierPartCode)
            {
                result.pricehidden = true;
                IEnumerable<dynamic> supplierParts = repository.Invoke(CSIs.Get_Supplier_Part_For_Nissan, new { result.partCode, brandCode });
                if (supplierParts != null && supplierParts.Any())
                {
                    result.partAttributes = supplierParts.Select(q => new Query_Part_DetailResult._partAttribute
                    {
                        partCode = q.partCode,
                        brandCode = brandCode,
                        brandName = brandName,
                        marketCode = q.marketCode,
                        marketName = q.marketName,
                        cost = q.cost,
                        price = q.price,
                        priceUpdatedAt = q.priceUpdatedAt,
                        stock = q.stock,
                        priceFC = q.priceFC,
                        disabled = q.disabled == 1,
                        props = new List<Query_Part_DetailResult._prop> { new Query_Part_DetailResult._prop { key = "供应商配件号", value = q.partCode }, new Query_Part_DetailResult._prop { key = "禁用", value = q.disabled == 1 ? "是" : "否" } }
                    }).ToList();
                }
            }

            result.replacements = new List<Query_Part_DetailResult._replacement>();
            //3.替换件处理
            if (!string.IsNullOrEmpty(data.supersession))
            {
                List<Query_Part_DetailResult._replacement> replacements = repository.Invoke<Query_Part_DetailResult._replacement>(CSIs.Query_Parts_By_Codes, new { partCodes = data.supersession.Split(',') });
                var replacement = replacements.FirstOrDefault();
                if (replacement != null)
                {
                    replacement.brandCode = brandCode;
                    replacement.brandName = BrandDictionary.GetName(brandCode);
                    replacement.props = new List<Query_Part_DetailResult._prop>();
                    if (!string.IsNullOrEmpty(data.supersessionType))
                    {
                        replacement.props.Add(new Query_Part_DetailResult._prop { key = "替换类型", value = data.supersessionType });
                    }
                    IEnumerable<dynamic> repSupplierParts = repository.Invoke(CSIs.Get_Supplier_Part_For_Nissan, new { replacement.partCode, brandCode });
                    if (repSupplierParts != null && repSupplierParts.Any())
                    {
                        replacement.partAttributes = repSupplierParts.Select(q => new Query_Part_DetailResult._partAttribute
                        {
                            partCode = q.partCode,
                            brandCode = brandCode,
                            brandName = brandName,
                            marketCode = q.marketCode,
                            marketName = q.marketName,
                            cost = q.cost,
                            price = q.price,
                            priceUpdatedAt = q.priceUpdatedAt,
                            priceFC = q.priceFC,
                            disabled = q.disabled == 1,
                            props = new List<Query_Part_DetailResult._prop> { new Query_Part_DetailResult._prop { key = "供应商配件号", value = q.partCode }, new Query_Part_DetailResult._prop { key = "禁用", value = q.disabled == 1 ? "是" : "否" } }
                        }).ToList();
                    }
                    result.replacements.Add(replacement);
                }
            }
            //4.配件附加属性处理
            var props = new List<Query_Part_DetailResult._prop>
            {
                new Query_Part_DetailResult._prop { key = "件数", value = result.quantity ?? string.Empty },
                new Query_Part_DetailResult._prop { key = "生效日期", value = data.startTime?.ToString() ?? string.Empty },
                new Query_Part_DetailResult._prop { key = "有效日期", value = data.endTime?.ToString() ?? string.Empty},
                new Query_Part_DetailResult._prop { key = "Specification", value = data.specification?? string.Empty},
                new Query_Part_DetailResult._prop { key = "Spec Code", value = data.specCode?? string.Empty},
                new Query_Part_DetailResult._prop { key = "Trim Color", value = data.trimColor?? string.Empty},
                new Query_Part_DetailResult._prop { key = "Body Color", value = data.bodyColor?? string.Empty},
                new Query_Part_DetailResult._prop { key = "Country", value = data.country?? string.Empty},
                new Query_Part_DetailResult._prop { key = "禁用", value = data.disabled == 1?"是":"否"}
            };
            result.props = props.Where(q => !string.IsNullOrEmpty(q.value)).ToList();
            return result;
        }

        protected override dynamic GetModelsByPart(DbRESTFulRepository repository, int pageIndex, int pageSize, string brandCode, string partCode)
        {
            var supplierPart = repository.Invoke(CSIs.Get_Single_Supplier_Part_For_Nissan, new { supplierPartCode = partCode, brandCode });
            var realPartCode = "";
            if (supplierPart != null)
            {
                realPartCode = supplierPart.partCode;
            }
            else
            {
                realPartCode = partCode;
            }
            return repository.Invoke(CSIs.Query_Models_By_Part_For_Nissan, new { pageIndex, pageSize, brandCode, partCode = realPartCode });
        }

        protected override dynamic GetHotPointsByPart(DbRESTFulRepository repository, string brandCode, string partCode, IEnumerable<string> imageIds)
        {
            var supplierPart = repository.Invoke(CSIs.Get_Single_Supplier_Part_For_Nissan, new { supplierPartCode = partCode, brandCode });
            var realPartCode = "";
            if (supplierPart != null)
            {
                realPartCode = supplierPart.partCode;
            }
            else
            {
                realPartCode = partCode;
            }
            return repository.Invoke(CSIs.Query_HotPoints_By_Part_For_Nissan, new { brandCode, partCode = realPartCode, imageIds });
        }

        protected override List<SearchSubGroupResults> GetSearchResults(DbRESTFulRepository repository, string brandCode, string[] partCodes, string selectorId)
        {
            return repository.Invoke<SearchSubGroupResults>(CSIs.Search_SubGroups_By_PartCodes_For_Nissan, new { brandCode, partCodes, selectorId });
        }
    }
}



